
        
angular.module('theApp.app', [])

.run(function(root, $rootScope, $firebase) {

    // constants
    $rootScope.genders = ['Boys', 'Girls'];
    $rootScope.ages = ['U8', 'U9', 'U10', 'U11', 'U12', 'U13', 'U14', 'U15', 'U16', 'U17', 'U18', 'U19'];
    $rootScope.classes = ['Recreational', 'Competitive'];
    $rootScope.days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
    $rootScope.errors = {
        "0": "Unknown error.",
        "1000": "Cannot create team as guest or for another user.",
        "1001": "Attempt to load a non-existing record.",
        "1002": "Unable to update the unique id generator."
    };

    // variable cached upfront 
    $('#sswloader').show();
    $firebase(root.child('fields')).$asObject().$loaded(function(fa) {
        $rootScope.fieldsall = fa;
        $firebase(root.child('fields')).$asArray().$loaded(function(farr) {
            $rootScope.fieldsallarr = farr;
            $('#sswloader').hide();
        });
    });
})

.service('S', function() {

    return {
   
        type_specific: function($scope, type, me) {
            if (type === 'request') {
               $scope.fieldsallarr.forEach(function(f, i) {
                   if (f.uid === me.field1.uid) {
                       $scope.request.field1 = $scope.fieldsallarr[i];
                   }
                   if (f.uid === me.field2.uid) {
                       $scope.request.field2 = $scope.fieldsallarr[i];
                   }
               });
            }
        }, 

        add_new_parent: function($scope, type, pType, extra) {
            if ($scope[type][pType + 's'] === undefined) {
                $scope[type][pType + 's'] = {};
            }
            $scope[type][pType + 's'][extra] = true;        
        },

        type_specific_save_before: function($scope, type, parent, S) {

            $scope[type].owner = $scope.luser.uid;
            
            if (parent !== undefined) {
                var pType = S.parent_of(type);
                S.add_new_parent($scope, type , pType, parent);
            }
            
            if (type === 'request') {
                
                // Add selected fields to 'request.fields' (not the same
                // as field1 and field2
                var x = {};
                x[$scope[type].field1.uid] = 1;
                x[$scope[type].field2.uid] = 2;
                $scope[type].fields = x;
                
                $scope[type].name = '(name is being compiled)';
            }
        },
        
        register_with_parent: function(root, type, pType, extra) {

            var rRef = root.child(pType + 's').child(extra[0]).child(type + 's');  
            var data = {};
            data[extra[1]] = true;
            rRef.update(data);
        },

        child_of: function(type) {
            var pType = null;
            if (type === 'user') {
                pType = 'team';
            }
            else if (type === 'team') {
                pType = 'request';
            }
            else if (type === 'request') {
                pType = 'field';
            }
            return pType;
        },
        
        parent_of: function(type) {
            var pType = null;
            if (type === 'field') {
                pType = 'request';
            }
            else if (type === 'request') {
                pType = 'team';
            }
            else if (type === 'team') {
                pType = 'user';
            }
            return pType;
        },
        
        computeApprovalQueue: function(ref) {
            var ini = {field:0, approved:false, slot:0, day:0};
            ref.once('value', function(snap) {

                var r = snap.val();
                
                // Prepare empty matrix
                var fRange = [1, 2];
                var tRange = [1, 2];
                var m = [];
                fRange.forEach(function(nf) {                
                    var x = [];
                    m.push(x);
                    tRange.forEach(function(nt) {
                        var x = [];
                        m[nf - 1].push(x);
                    });
                });

                // collect data in NxN matrix
                fRange.forEach(function(nf) {                
                    var a = [];
                    var ap = ini;
                    ap.field = r['field' + nf].uid;
                    ap.slot = r['time' + nf];
                    tRange.forEach(function(nt) {
                        var a = [];
                        
                        // a bit of a hack. Reorder days from most wanted to less wanted
                        ['Thu','Tue','Wed','Fri','Mon'].forEach(function(day) {
                            if (r['day' + nt + day] === true) {
                                ap.day = day;
                                m[nf - 1][nt - 1].push(angular.copy(ap));
                            }
                        });
                    });                    
                });
                
                // sort matrix elements so that 1,1 is first and N,N is last
                // and update the record on the fly.
                ref.child('approved').set({});
                ref.child('original').set({});
                var rapp =  ref.child('submitted');
                rapp.set({});
                var index = 0;
                fRange.forEach(function(nf) {
                    tRange.forEach(function(nt) {    
                        var a = m[nf - 1][nt - 1];
                        a.forEach(function(e) {
                            e.index = index;
                            index++;
                            rapp.push(e);
                        });
                    });
                });                
            });
        },
        
        type_specific_save_after: function(root, $scope, $rootScope, $firebase, type, ref, S) {
            
            if (type === 'user') {
                $rootScope.luser = $firebase(ref).$asObject();
            }
            
            if (type === 'request') {
                var teamRef = root.child('teams').child(Object.keys($scope[type].teams)[0]);
                teamRef.once('value', function(teamSnap) {
                    ref.once('value', function(reqSnap) {
                        ref.update({name: reqSnap.val().mapid + '-' + teamSnap.val().name});
                        S.computeApprovalQueue(ref);
                    });
                });
            }
        },
        
        validate_form: function($scope, $rootScope, type) {
            var error  = '';
            if (type === 'request') {
                if ($scope.requestEditing === true) {
                    var r = $scope.request;
                    var sessnum = parseInt(r.sessions);
                    if (sessnum < 1 || sessnum > 3 || isNaN(sessnum)) {
                        error += "Number of sessions per week must be 1,2, or 3.";
                    }                    
                    var dayCount1 = 0;
                    var dayCount2 = 0;
                    $rootScope.days.forEach(function(d) {
                        if (r['day1' + d] === true) {
                            dayCount1 += 1;
                        }
                        if (r['day2' + d] === true) {
                            dayCount2 += 1;
                        }
                    });
                    if (dayCount1 !== sessnum || dayCount2 !== sessnum) {
                        error += "Requested days ("+dayCount1+' '+dayCount2+") do not match number of sessions per week = " + sessnum;
                    }
                    if (r.purpose !== 'Practice' && r.purpose !== 'Scrimmage') {
                        error += "Request purpose must be Scrimmage or Practice";
                    }
                }
            }
            if (error === '') {
                return true;
            }
            alert('*** ERROR IN FORM *** ' + error);
            return false;
        },
            
        find_by_field: function(list, field, value, one) {
            var ret = [];
            var elm = null;
            if (list instanceof Array) {
                for (var i = 0; i < list.length; i++) {
                    elm = list[i];
                    if (elm[field] == value) { 
                        ret.push(elm);     
                        if (one) {
                            return ret;
                        }
                    }
                }
                return ret;
            } 
            var keys = list.$getIndex();
            keys.forEach(function(key, i) {
                // use == because we compare string to number
                elm = list.$child(key);
                if (elm[field] === value+'') { 
                    ret.push(elm);
                        if (one) {
                            return;
                        }
                }
            });
            return ret;
        },
        
        controller_one:  function(root, $scope, $rootScope, $firebase, $location, $route, S, type, nextAction, uid) {

            var saved = {};
            var savedinfo = {};
            
            $scope.edit = function(t) {
                saved = angular.copy($scope[t]);
                savedinfo = angular.copy($scope[t + 'info']);
                $scope[t + 'Editing'] = true;
            }; 
            
            $scope.cancel = function(t) {
                $scope[t] = angular.copy(saved);
                $scope[t + 'info'] = angular.copy(savedinfo);
                $scope[t + 'Editing'] = false;
                $route.reload();
            };

            $scope.destroy = function(t) {
                var yn = prompt("Are you sure you want to delete this " + t + "? Type YES if you are", "NO");
                if (yn === "YES") {
                    alert('*** WARNING *** Destruction of components is not supported yet');
                }
            };

            $scope.save = function(t) {

                if (!S.validate_form($scope, $rootScope, type)) {
                    return;
                }

                S.type_specific_save_before($scope, type, null, S);

                if (true === confirm("Save the changes?")) {
                    $scope[t].$save().then(function(x) {
                        $scope[t + 'Editing'] = false;
                        var p = $firebase(x).$asObject();
                        p.$loaded(function(me) {

                            // custom actions such as relations with other objects
                            S.type_specific_save_after(root, $scope, $rootScope, $firebase, type, x, S);

                            $route.reload();
                            //alert('Information for this ' + t + ' was updated');
                        });
                    })
                    .catch(function(err) {
                        console.log(err);
                        $scope[t + 'Editing'] = false;
                        alert('*** ERROR *** \nInformation for this ' + t + 'was NOT updated');
                    });
                }
            };

            $scope[type + 'Detail'] = false;
            $scope[type] = {};
            
            var thingRef = root.child(type + 's').child(uid);
            thingRef.once('value', function(thingSnap) {
     
                if (thingSnap.val() === null) {
                    console.log(type + ' with id ' +  uid + ' not found.');
                    $location.path('/error/1001');
                    
                } else {

                    // Valid current item
                    var thingSync = $firebase(thingRef);
                    var thing = thingSync.$asObject();
                    thing.$loaded(
                        function(me) {
                            console.log(me + ' ' + $rootScope.luser);

                            $scope[type] = me;
                            $scope[type + 'Detail'] = true;
                            $scope[type + 'Editing'] = false;
                            $scope[type + 's'] = [me];
                                                                                     
                            if (nextAction !== undefined) {
                                nextAction.apply(this, [[me]]);
                            }
                            
                            S.type_specific($scope, type, me);
                        },
                        function(err) {
                            console.log(err);
                        }
                    );
                }
            });
        },
        
        controller_some: function(root, $scope, $firebase, type, sources, nextAction, noParents) {

            $scope[type + 's'] = [];
                    
            if (!(sources instanceof Array)) {
                $scope[type + 's'] = $firebase(root.child(type + 's')).$asArray();
                return;
            }
            
            if (noParents === true) {

                var v = [];
                var snaps = $firebase(root.child(type + 's')).$asArray();
                var c = snaps.length;
                snaps.$loaded().then(function(rr) {
                    rr.forEach(function(r, j) {
                        if (r['fields'][sources[0].uid] !== undefined) {
                            v.push(r);
                        }
                    });
                    $scope[type + 's'] = v;
                    if (nextAction !== undefined) {
                        nextAction.apply(this, [v]);
                    }

                }).catch(function(err) {
                    console.log(err);
                });
                
                return;
            }
             
            // WARNING! The elements here must be collected synchronously
            // because we cannot go to the next action until all have been
            // gathered. To do this, I collect the snapshot synchronously
            // and then load them asynchronously but I count the callbacks
            // at the end, so I know when I am done.
            var v = [];
            var pos = 0;
            sources.forEach(function(client, j) {
                var ob = client[type + 's'];
                if (ob !== undefined) {                    
                    Object.keys(ob).map(function (e, i) {                        
                        v.push($firebase(root.child(type + 's').child(e)).$asObject());
                        pos++;
                    });
                }
            });

            var w = [];
            var s = {};
            var c = v.length;
            v.forEach(function(x, i) {
                c--;
                x.$loaded().then(function(e) {
                    if (s[e.uid] === undefined) {
                        s[e.uid] = true;
                        w.push(e);
                    }
                    if (c === 0) {
                        $scope[type + 's'] = w;
                        if (nextAction !== undefined) {
                            nextAction.apply(this, [w]);
                        }
                    }
                }).catch(function(err) {
                    console.log(err);
                });
            });
        },

        set_defaults: function($scope, type) {
            $scope[type] = {};
            if (type === 'team') {
                $scope[type].name = '-- team name --';
                $scope[type].age = 'U12';
                $scope[type].gender = 'Boys';
                $scope[type].class = 'Recreational';
            }
            if (type === 'request') {
                //$scope[type].approved = false;
            }
        },
        
        controller_create: function(root, $scope, $rootScope, $firebase, $location, $route, parent, S, type) {   
            
            if ($rootScope.luser === null || $rootScope.luser === undefined) {
                $location.path('/error/1000');
                return;
            }

            var list = $firebase(root.child(type + 's')).$asArray();
            $scope[type + 's'] = $firebase(root.child(type + 's')).$asArray(); 
            
            $scope[type + 'Detail'] = true;
            $scope[type + 'Editing'] = true;
            
            S.set_defaults($scope, type);
            
            $scope.cancel = function() {
                $location.path('/' + S.parent_of(type) + '/' + parent);
            };

            $scope.save = function() {

                if (!S.validate_form($scope, $rootScope, type)) {  
                    return;
                }
                
                // custom actions such as relations with other objects
                S.type_specific_save_before($scope, type, parent, S);

                list.$add($scope[type]).then(function(ref) {
                    var uid = ref.name();
                    console.log('Saved new object ', uid, ' at ', list.$indexFor(uid));
                        
                    // add unique id 
                    var countRef = root.child('count_id');
                    countRef.transaction(function(count) {
                        return count+1;
                    },
                    function(error, committed, snap) {
                        
                        if (error) {
                            console.log('Unable to update count_id');
                            $location.path('/error/1002');
                            return;
                        }
                        var mapid = snap.val();
                      
                        console.log('New count: ', mapid);
                              
                        // add unique id and mapid
                        ref.update({"mapid" : mapid, "uid" : uid});
                        var pType = S.parent_of(type);
                        if (pType !== null) {
                            S.register_with_parent(root, type, pType, [parent, uid]);
                        }

                        S.type_specific_save_after(root, $scope, $rootScope, $firebase, type, ref, S);

                        console.log('New item was assigned unique id and self id: ', mapid);
                        $scope[type + 'Editing'] = false;

                        $location.path('/' + type + '/' + uid);
                        $route.reload();
                    });                                
                }).catch(function(err) {console.log('Cannot add new object: ', err);});
            };

        }
         
    };
  
})
    
.controller('requestController', function(root, $scope, $rootScope, $firebase, $filter, $location, $route, $routeParams, S) {
    $scope.requestFocus = true;
    S.controller_one(root, $scope, $rootScope, $firebase, $location, $route, S, 'request', function(ids) {
        S.controller_some(root, $scope, $firebase, 'field', ids);
        S.controller_some(root, $scope, $firebase, 'team', ids, function(ids) {
            S.controller_some(root, $scope, $firebase, 'user', ids);            
        });
     }, $routeParams.id);
})

.controller('teamController', function(root, $scope, $rootScope, $firebase, $filter, $location, $route, $routeParams, S) {
    $scope.teamFocus = true;
    S.controller_one(root, $scope, $rootScope, $firebase, $location, $route, S, 'team', function(ids) {
        S.controller_some(root, $scope, $firebase, 'user', ids);
        S.controller_some(root, $scope, $firebase, 'request', ids);
    }, $routeParams.id);    
 })
    
.controller('userController', function(root, $scope, $rootScope, $firebase, $filter, $location, $route, $routeParams, S) {
    $scope.userFocus = true;
    S.controller_one(root, $scope, $rootScope, $firebase, $location, $route, S, 'user', function(ids) {
        S.controller_some(root, $scope, $firebase, 'team', ids);
    }, $routeParams.id);
 })

.controller('fieldController', function(root, $scope, $rootScope, $firebase, $filter, $location, $route, $routeParams, S) {
    $scope.fieldFocus = true;
    S.controller_one(root, $scope, $rootScope, $firebase, $location, $route, S, 'field', function(ids) {
        S.controller_some(root, $scope, $firebase, 'request', ids, function(ids) {
            S.controller_some(root, $scope, $firebase, 'team', ids, function(ids) {
                S.controller_some(root, $scope, $firebase, 'user', ids);
            });
        }, true);
    }, $routeParams.id);
 })
 
.controller('fieldsController', function(root, $rootScope, $firebase, S) {
//    S.preamble(root, $rootScope, $firebase);
})

.controller('allController', function(root, $scope, $firebase, $filter, S) {
    S.controller_some(root, $scope, $firebase, 'user',    true);
    S.controller_some(root, $scope, $firebase, 'team',    true);
    S.controller_some(root, $scope, $firebase, 'request', true);
    S.controller_some(root, $scope, $firebase, 'field',   true);
   
})
    
.controller('teamControllerCreate', function(root, $scope, $rootScope, $firebase, $location, $route, $routeParams, S) {
    S.controller_create(root, $scope, $rootScope, $firebase, $location, $route, $routeParams.id, S, 'team');
})

.controller('requestControllerCreate', function(root, $scope, $rootScope, $firebase, $location, $route, $routeParams, S) {
    S.controller_create(root, $scope, $rootScope, $firebase, $location, $route, $routeParams.id, S, 'request');
})

.controller('scheduleController', function($scope, root, $rootScope, $firebase, $route, $routeParams, S) {

    $scope.switchApproved = function() {
        $rootScope.approved = !$scope.approved;
        $route.reload();
    };

    $scope.approve = function(x) {
        // mark this request case as approved
        x.ap.approved = true;
        //root.child('requests').child(x.r.uid).child('submitted').child(x.ak).set(x.ap);
        // if all sessions are satisfied, hide the remaining cases
        var count = x.r.sessions;
        var aarr = [];
        var daysToHide = {};
        Object.keys(x.r.submitted).map(function(k) {
            var e = x.r.submitted[k];
            if (e.approved) {
                count--;
                aarr.push(e);
                daysToHide[e.day] = true;
            }
        });
        Object.keys(x.r.submitted).map(function(k) {
            var g = x.r.submitted[k];
            g.hidden = false;
            if (!g.approved) {
                if (daysToHide[g.day] === true) {
                    g.hidden = true;
                }
            }
        });
        if (count === 0) {
            x.r.original = x.r.submitted;
            x.r.submitted = {};
            x.r.approved = aarr;
        }
        root.child('requests').child(x.r.uid).set(x.r);
        $route.reload();
    };

    if ($rootScope.approved === undefined) {
        $rootScope.approved = true;
    };

    //$('#sswloader').show();

    var fid = $routeParams.fid;
    var tid = $routeParams.tid;
    var tchosen = null;
    var fchosen = null;


    if (fid !== 'all') {
        fchosen = fid;
    }
    if (tid !== 'all') {
        tchosen = tid;
    }

    // Create the scaffolding with emtpy cells. This is always
    // there. Later we fill the cells as needed.
    var varr = [];
    var d = {};
    $scope.fieldsallarr.forEach(function(field) {
        $scope.field = field;
        varr.push(field);
        d[field.uid] = {};
        d[field.uid].field = field;
        d[field.uid].show = (fchosen === null && tchosen === null || field.uid === fchosen);
        var slots = field.slots;
        slots.forEach(function(slot) {
            d[field.uid][slot] = {};
            $scope.days.forEach(function(day) {
                d[field.uid][slot][day] = [];
            });
        });
    });

    $scope.d = d;

    // scan all requests, and put them in the corresponding cell of the grid.
    root.child('requests').once('value', function(rs) {
        var reqAll = rs.val();
        angular.forEach(reqAll, function(r) {
            $('#sswloader').show();
            var team = $firebase(root.child('teams').child(Object.keys(r.teams)[0])).$asObject();
            team.$loaded(function() {

                $('#sswloader').hide();
                // If there is a chosen team and not this one, skip this team.
                if (team.uid !== tchosen && null !== tchosen) {
                    return;
                }

                if (r.submitted instanceof Object) {

                    // put submitted requests in scope
                    var i = 0;
                    Object.keys(r.submitted).map(function(key) {

                        i++;
                        var ap = r.submitted[key];

                        // If there is a chosen field and this request does not use it, skip.
                        if (fchosen !== null && fchosen !== ap.field) {
                            return;
                        }

                        var status = ap.approved ? 'approved' : ap.hidden ? 'hidden' : 'submitted';

                        var box = {"r": r, "ak": key, "t": team, "n": i, "ap": ap, status: status};

                        if (ap.approved || !$scope.approved) {
                            $scope.d[ap.field][ap.slot][ap.day].push(box);
                            $scope.d[ap.field].show = true;
                        }
                    });
                }

                if (r.approved instanceof Object) {

                    // put approved requests in scope
                    var i = 0;
                    Object.keys(r.approved).map(function(key) {

                        i++;
                        var ap = r.approved[key];

                        // If there is a chosen field and this request does not use it, skip.
                        if (fchosen !== null && fchosen !== ap.field) {
                            return;
                        }

                        var box = {"r": r, "ak": key, "t": team, "n": i, "ap": ap, status: 'complete'};

                        $scope.d[ap.field][ap.slot][ap.day].push(box);
                        $scope.d[ap.field].show = true;
                    });
                }
            });
        });

    });
})

.controller('serverController', function($scope, $http, A) {

    A.send_email($http, $scope, "mlchiodo@gmail.com", "someone@somewhere.com", "a-test-subject", 'this is the text of my message');
    return;
    
    
    var srv = "php/server.php";
    
    //
    //var x = {'op': 'email', 'data': {"a": "111", "b": "222"}};

    $scope.aaa = " Sent ";

    $http.post(srv, {'payload': x})

    .success(function(data, status, headers, config) {

        $scope.aaa += " after-post: " + JSON.stringify(data);

        $http.get('php/read.php').success(function(data, status, headers, config) {

            $scope.aaa += " after-get: " + data;
        })

        .error(function(data, status, headers, config) {
        });

    }).error(function(data, status, headers, config) {
    });


    $scope.aaa += ' Waiting ... ';
 })
 
// mmmmmmmm

.controller('testController', function($scope) {
    $scope.title = 'Eccolo';
    
    
 })

;




